﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../global/head.h"
#include "../logger/head.h"
#include "../msg/head.h"
#include "helper_log.h"
#include "log_impl.h"
#include "config.h"

namespace xos_log
{

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    log_impl::log_impl()
    {
        init_data();
    }

    log_impl::~log_impl()
    {
        if( g_pSysData )
        {
            g_pSysData->term();
            delete g_pSysData;
            g_pSysData = 0;
        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // 使用日志功能
    // 
    int log_impl::log_info( const char * lpszName, int ulLevel, const char * lpszCodeFile, int ulCodeLine, const char * lpszFmt, ... )
    {
        int ret = 0;

        log_msg * pMsg = 0;

        if( ( 0 == ret ) && !m_bEnableLog )
        {
            ret = 1;
        }

        if( 0 == ret )
        {
            pMsg = log_msg::get_item_from_pool( true );
            pMsg->init();
        }

        if( 0 == ret )
        {
            pMsg->m_nSrcCodeLine = ulCodeLine;
            pMsg->m_file = lpszCodeFile;
            pMsg->m_nLevel = ulLevel;
            pMsg->m_name = lpszName;
        }

        if( 0 == ret )
        {
            char info[10240];
            va_list ap;
            va_start( ap, lpszFmt );
            g_pSysData->m_pContainer->crt()->vsnprintf( info, sizeof( info ), lpszFmt, ap );
            va_end( ap );
            pMsg->m_log = info;
        }

        if( 0 == ret )
        {
            notify( enumMsg::MSG_LOG, pMsg );
            pMsg = 0;
        }

        return ret;
    }

    int log_impl::flush()
    {
        int ret = 0;
        notify( enumMsg::MSG_FLUSH_LOG, 0 );
        return ret;
    }

    // 
    // 设置公共线程，所有日志消息都扔到这个线程中处理。公用线程能节省，少用一些线程，代码也清楚一些
    // 
    int log_impl::set_work_thread( xos_box::i_callback * pWorkThread )
    {
        int ret = 0;
        g_pSysData->m_pWorkThread = pWorkThread;
        return ret;
    }

    // 
    // 通过xml配置文件设置参数.和通过读取XML内容设置
    // 
    int log_impl::set_config_string( const char * lpszConfigString )
    {
        int nRet = 0;

        config tool( this );
        tool.load_config_string( lpszConfigString );

        return nRet;
    }

    int log_impl::set_config_file( const char * lpszConfigFile )
    {
        int nRet = 0;

        config tool( this );
        tool.load_config_file( lpszConfigFile );

        return nRet;
    }

    // 
    // 手动设置参数
    // 
    int log_impl::add_log_module( const char * lpszModuleName, int ulLevel )
    {
        using namespace std;
        int nRet = 0;

        log_module * pModule = 0;

        if( 0 == nRet )
        {
            pModule = g_pSysData->find_log_module( lpszModuleName );

            if( !pModule )
            {
                pModule = log_module::get_item_from_pool( true );
                pModule->init();
                g_pSysData->m_pContainer->crt()->strcpy( pModule->m_szName, sizeof( pModule->m_szName ), lpszModuleName );
                log_module::list()->push_back( pModule );
            }
        }

        if( 0 == nRet )
        {
            log_level * pLevel = pModule->find_log_level( ulLevel );

            if( !pLevel )
            {
                pLevel = log_level::get_item_from_pool( true );
                pLevel->init();
                pLevel->m_nLevel = ulLevel;
                pModule->level_list_ptr->push_back( pLevel );
            }
        }

        return nRet;
    }

    // 
    // 创建日志输出方式
    // 
    int log_impl::create_logger( enumLogObject enumType, void ** ppv )
    {
        int nRet = 0;

        *ppv = 0;

        switch( enumType )
        {
        case enumLogObject::LOG_OBJECT_LOGGER_DEBUG:  // OutputDebugString
            {
                *ppv = new log_debug::T;
            }
            break;
        case enumLogObject::LOG_OBJECT_LOGGER_FILE:   // File
            {
                *ppv = new log_file::T;
            }
            break;
        case enumLogObject::LOG_OBJECT_LOGGER_CMD:    // cmd
            {
                *ppv = new log_cmd::T;
            }
            break;
        case enumLogObject::LOG_OBJECT_LOGGER_NET:    // net
            {
                nRet = 1;
            }
            break;
        default:
            {
                nRet = 1;
            }
            break;
        }

        if( !( *ppv ) )
        {
            nRet = 1;
        }

        return nRet;
    }

    // 
    // 添加日志输出方式
    // 
    int log_impl::add_logger( i_logger * pLogger )
    {
        int nRet = 0;

        logger * p = logger::get_item_from_pool( true );
        p->init();
        p->m_pLogger = pLogger;
        logger::list()->push_back( p );

        return nRet;
    }

    // 
    // 日志开关
    // 
    int log_impl::enable( bool bEnable )
    {
        int ret = 0;

        m_bEnableLog = bEnable;

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    // xos::i_runnable method
    // 
    int log_impl::run_task( xos_box::i_msg *& pMsg )
    {
        int ret = 0;

        enumMsg eMsg = (enumMsg)pMsg->get_int( 0, 0 );

        switch( eMsg )
        {
        case enumMsg::MSG_LOG:
            {
                log_impl::proc_log( pMsg );
            }
            break;
        case enumMsg::MSG_FLUSH_LOG:
            {
                log_impl::flush_log();
            }
            break;
        default:
            {
            }
            break;
        }

        xos_stl::release_interface( pMsg );

        return ret;
    }

    int log_impl::flush_log()
    {
        int ret = 0;

        for( logger::ITER i = logger::list()->begin(); i != logger::list()->end(); ++i )
        {
            logger * p = *i;
            p->m_pLogger->flush();
        }

        return ret;
    }

    int log_impl::proc_log( xos_box::i_msg * pMsg )
    {
        int ret = 0;

        log_msg * pLogMsg = 0;

        if( 0 == ret )
        {
            pLogMsg = (log_msg *)pMsg->get_void( 0, 0 );
        }

        if( 0 == ret )
        {
            helper_log obj;
            ret = obj.proc_log( pLogMsg );
            pLogMsg = 0;
        }

        return ret;
    }

    // 
    // 通知线程写日志
    // 
    int log_impl::notify( enumMsg eMsg, void * lpData )
    {
        int ret = 0;

        xos_box::i_msg * pMsg = 0;

        if( 0 == ret )
        {
            pMsg = g_pSysData->m_pContainer->msg();
        }

        if( 0 == ret )
        {
            pMsg->set_int( 0, (int)eMsg );
            pMsg->set_runnable( 0, log_impl::run_task );
            pMsg->set_void( 0, lpData );
            g_pSysData->m_pWorkThread->notify( pMsg );
            pMsg = 0;
        }

        return ret;
    }

    int log_impl::init_data()
    {
        int ret = 0;
        m_bEnableLog = true;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int log_impl::put_back_to_pool( T * pT, bool bLock )
    {
        int ret = 0;
        delete this;
        return ret;
    }

    int log_impl::init()
    {
        int ret = 0;
        return ret;
    }

    int log_impl::term()
    {
        int ret = 0;
        init_data();
        return ret;
    }

} // xos_log
